package com.niiwoo.civet.account.service.local;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.rpc.RpcContext;
import com.niiwoo.civet.account.dao.entity.AccountBase;
import com.niiwoo.civet.account.dao.entity.ProjectInvestCustodyOrder;
import com.niiwoo.civet.account.dao.mapper.ProjectInvestCustodyOrderMapperExt;
import com.niiwoo.civet.account.dto.bill.AddBillAndChangeBalanceDTO;
import com.niiwoo.civet.account.dto.bill.AddBillDetailDTO;
import com.niiwoo.civet.account.dto.bill.BillIntelligenceInvestForMahchRequest;
import com.niiwoo.civet.account.dto.common.MoneyTotalDTO;
import com.niiwoo.civet.account.dto.common.ProjectInvestCancelOrderDTO;
import com.niiwoo.civet.account.dto.common.ProjectInvestCustodyOrderDTO;
import com.niiwoo.civet.account.dto.request.InvestPayDubboRequestDTO;
import com.niiwoo.civet.account.enums.AccountAmountTypeEnum;
import com.niiwoo.civet.account.enums.BillRemark3Enum;
import com.niiwoo.civet.account.enums.BillSecondSubjectEnum;
import com.niiwoo.civet.account.enums.BillStatusEnum;
import com.niiwoo.civet.account.enums.InoutTypeEnum;
import com.niiwoo.civet.account.enums.OrderTypeEnum;
import com.niiwoo.civet.account.service.dubbo.AccountInvestDubboServiceImpl;
import com.niiwoo.civet.account.service.local.bill.BillFacade;
import com.niiwoo.civet.base.enums.BorrowProjectTypeEnum;
import com.niiwoo.civet.base.enums.ChannelCodeEnum;
import com.niiwoo.civet.trade.dto.common.ProjectDTO;
import com.niiwoo.civet.trade.dto.response.intelligenceInvest.IntelligencePayInfoResponseDTO;
import com.niiwoo.civet.trade.enums.LoanTypeEnum;
import com.niiwoo.civet.trade.enums.OrderInvestTypeEnum;
import com.niiwoo.civet.trade.service.intelligenceInvest.IntelligenceInvestDubboService;
import com.niiwoo.civet.trade.service.project.ProjectDubboService;
import com.niiwoo.tripod.lanmao.component.LanMaoSequence;
import com.niiwoo.tripod.lanmao.enums.UserRoleEnum;
import com.niiwoo.tripod.provider.exception.BizException;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;

@Service
public class AccountInvestService {

	private static final Logger logger = LoggerFactory.getLogger(AccountInvestDubboServiceImpl.class);

	@Autowired
	private SnowflakeIdWorker snowflakeIdWorker;
	@Autowired
	private ProjectInvestCustodyOrderMapperExt projectInvestCustodyOrderMapperExt;
	@Autowired
	private LanMaoSequence lanMaoSequence;
	@Autowired
	private BillFacade billFacade;
	@Autowired
	private MoneyTotalLocalService moneyTotalLocalService;
	@Autowired
	private AccountService accountService;
	@Reference(version = "1.0.0")
	private ProjectDubboService projectDubboService;
    @Reference(version = "1.0.0")
    private IntelligenceInvestDubboService intelligenceInvestDubboService;
	/**
	 * 生成投资支付存管订单
	 *
	 * @param investPayDubboRequestDTO
	 * @return
	 */
	@Transactional
	public ProjectInvestCustodyOrder generateInvestCustodyOrder(InvestPayDubboRequestDTO investPayDubboRequestDTO) {
		// 个人查询不存在查询机构
		AccountBase accountBase = accountService.getNiiwooAccount(investPayDubboRequestDTO.getUserId(), UserRoleEnum.INVESTOR);
		if (Objects.isNull(accountBase)) {
			accountBase = accountService.getOrgAccount(investPayDubboRequestDTO.getUserId(), investPayDubboRequestDTO.getUserId());
		}
		if (Objects.isNull(accountBase)) {
			throw new BizException("ACC10001");// 存管账户未开通
		}
		ProjectInvestCustodyOrder record = new ProjectInvestCustodyOrder();
		record.setId(snowflakeIdWorker.nextId());
		record.setInvestOrderId(investPayDubboRequestDTO.getInvestOrderId());
		record.setInvestType(investPayDubboRequestDTO.getInvestType());
		record.setUserId(investPayDubboRequestDTO.getUserId());
		record.setAccountId(accountBase.getId());
		// 债权投资时候，标的ID使用债权出让ID
		if (Byte.valueOf("1").equals(investPayDubboRequestDTO.getInvestType())) {
			record.setProjectId(investPayDubboRequestDTO.getProjectId());
		} else {
			record.setProjectId(investPayDubboRequestDTO.getCreditsaleId());
		}
		record.setBorrowUserId(investPayDubboRequestDTO.getBorrowerUserId());
		record.setProjectType(investPayDubboRequestDTO.getProjectType());
		record.setProjectTitle(investPayDubboRequestDTO.getProjectTitle());
		record.setDeadline(investPayDubboRequestDTO.getDeadline());
		record.setDeadlineUnit(investPayDubboRequestDTO.getDeadlineUnit());
		record.setRequestNo(lanMaoSequence.getRequestNo());
		record.setPlatformUserNo(accountBase.getAccountNo());
		record.setProjectNo(String.valueOf(investPayDubboRequestDTO.getProjectId()));
		record.setAmount(investPayDubboRequestDTO.getInvestAmount());
		record.setShare(investPayDubboRequestDTO.getShare());
		record.setCreditSaleRequestNo(investPayDubboRequestDTO.getCreditsaleRequestNo());
		record.setCreateTime(new Date());
		projectInvestCustodyOrderMapperExt.insertSelective(record);
		return record;
	}

	/**
	 * 存管投资订单成功处理
	 *
	 * @param requestNo
	 * @return
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public Long projectInvestCustodyOrderSuccessHandle(String requestNo) {
		ProjectInvestCustodyOrder projectInvestCustodyOrder = projectInvestCustodyOrderMapperExt.selectByRequestNo(requestNo);
		if (!Byte.valueOf("0").equals(projectInvestCustodyOrder.getStatus())) {
			return projectInvestCustodyOrder.getInvestOrderId();
		}
		ProjectInvestCustodyOrder projectInvestCustodyOrderForUpdate = projectInvestCustodyOrderMapperExt.selectByPrimaryKeyForUpdate(projectInvestCustodyOrder.getId());
		if (!Byte.valueOf("0").equals(projectInvestCustodyOrderForUpdate.getStatus())) {
			return projectInvestCustodyOrder.getInvestOrderId();
		}
		ProjectInvestCustodyOrder record = new ProjectInvestCustodyOrder();
		record.setId(projectInvestCustodyOrderForUpdate.getId());
		record.setStatus(Byte.valueOf("1"));
		projectInvestCustodyOrderMapperExt.updateByPrimaryKeySelective(record);

		// 投资人投资冻结金额
		MoneyTotalDTO investFreeze = new MoneyTotalDTO();
		investFreeze.setAmountType(AccountAmountTypeEnum.INVEST_FREEZE);
		investFreeze.setAmount(projectInvestCustodyOrderForUpdate.getAmount());
		investFreeze.setUserId(projectInvestCustodyOrderForUpdate.getUserId());
		investFreeze.setAccountId(projectInvestCustodyOrderForUpdate.getAccountId());
		moneyTotalLocalService.moneyTotal(investFreeze);

		// 变更余额 + 记账
		AddBillDetailDTO addBillDetailDTO = new AddBillDetailDTO();
		addBillDetailDTO.setAmount(projectInvestCustodyOrderForUpdate.getAmount());
		addBillDetailDTO.setBillSecondSubjectEnum(BillSecondSubjectEnum.USER_INVEST);

		AddBillAndChangeBalanceDTO billDTO = new AddBillAndChangeBalanceDTO();
		billDTO.setAccountId(projectInvestCustodyOrderForUpdate.getAccountId());
		billDTO.setAmount(projectInvestCustodyOrderForUpdate.getAmount());
		billDTO.setInoutType(InoutTypeEnum.OUT_TYPE);
		billDTO.setProjectId(projectInvestCustodyOrderForUpdate.getProjectId());
		billDTO.setInvestId(projectInvestCustodyOrderForUpdate.getInvestOrderId());
		billDTO.setOrderId(projectInvestCustodyOrderForUpdate.getInvestOrderId());
		billDTO.setOrderType(OrderTypeEnum.INVEST);
		billDTO.setRequestNo(projectInvestCustodyOrderForUpdate.getRequestNo());
		billDTO.setStatus(BillStatusEnum.HANDLING);
		billDTO.setProjectType(BorrowProjectTypeEnum.enumOf(projectInvestCustodyOrderForUpdate.getProjectType()));
		billDTO.setProjectTitle(projectInvestCustodyOrderForUpdate.getProjectTitle());
		billDTO.setChannelCode(ChannelCodeEnum.APP);
		billDTO.setAddBillDetailDTOList(Arrays.asList(addBillDetailDTO));
		billDTO.setRelationUserId(projectInvestCustodyOrderForUpdate.getBorrowUserId());// 债权时 已处理成出让人
		// 债权的时候 关系人是 出让人
		if (Byte.valueOf("2").equals(projectInvestCustodyOrderForUpdate.getInvestType())) {
			AccountBase accountBase = accountService.getNiiwooAccount(projectInvestCustodyOrderForUpdate.getBorrowUserId(), UserRoleEnum.INVESTOR);
			billDTO.setRelationAccountId(accountBase.getId());
		} else {
			ProjectDTO projectDTO = projectDubboService.selectProjectById(projectInvestCustodyOrderForUpdate.getProjectId());
			billDTO.setRelationAccountId(projectDTO.getBorrowAccountId());
		}

		billFacade.addBillAndChangeBalance(billDTO);

		return projectInvestCustodyOrder.getInvestOrderId();
	}

	/**
	 * 存管投资订单失败处理
	 *
	 * @param requestNo
	 * @return
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public Long projectInvestCustodyOrderFailHandle(String requestNo) {
		ProjectInvestCustodyOrder projectInvestCustodyOrder = projectInvestCustodyOrderMapperExt.selectByRequestNo(requestNo);
		if (!Byte.valueOf("0").equals(projectInvestCustodyOrder.getStatus())) {
			return projectInvestCustodyOrder.getInvestOrderId();
		}
		ProjectInvestCustodyOrder projectInvestCustodyOrderForUpdate = projectInvestCustodyOrderMapperExt.selectByPrimaryKeyForUpdate(projectInvestCustodyOrder.getId());
		if (!Byte.valueOf("0").equals(projectInvestCustodyOrderForUpdate.getStatus())) {
			return projectInvestCustodyOrder.getInvestOrderId();
		}
		ProjectInvestCustodyOrder record = new ProjectInvestCustodyOrder();
		record.setId(projectInvestCustodyOrderForUpdate.getId());
		record.setStatus(Byte.valueOf("2"));
		projectInvestCustodyOrderMapperExt.updateByPrimaryKeySelective(record);

		return projectInvestCustodyOrder.getInvestOrderId();
	}

	/**
	 * 获取存管投资订单
	 *
	 * @param investOrderId
	 * @return
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public ProjectInvestCustodyOrder queryProjectInvestCustodyOrder(Long investOrderId) {
		return projectInvestCustodyOrderMapperExt.selectByInvestOrderIdAndType(investOrderId, Byte.valueOf("1"));
	}

	/**
	 * 通过投资订单ID列表查询存管投资订单列表
	 *
	 * @param investOrderIdSet
	 * @return
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public List<ProjectInvestCustodyOrderDTO> queryProjectInvestCustodyOrderListByInvestOrderIdSet(Set<Long> investOrderIdSet) {
		List<ProjectInvestCustodyOrderDTO> result = new ArrayList<ProjectInvestCustodyOrderDTO>();
		List<ProjectInvestCustodyOrder> projectInvestCustodyOrderList = projectInvestCustodyOrderMapperExt.queryProjectInvestCustodyOrderListByInvestOrderIdSet(investOrderIdSet);
		if (projectInvestCustodyOrderList != null) {
			for (ProjectInvestCustodyOrder projectInvestCustodyOrder : projectInvestCustodyOrderList) {
				if (projectInvestCustodyOrder != null) {
					ProjectInvestCustodyOrderDTO dto = new ProjectInvestCustodyOrderDTO();
					BeanUtils.copyProperties(projectInvestCustodyOrder, dto);
					result.add(dto);
				}
			}
		}
		return result;
	}

	/**
	 * 通过投资订单ID列表查询存管投资订单列表
	 *
	 * @param requestNoList
	 * @return
	 */
	public List<ProjectInvestCustodyOrderDTO> queryProjectInvestCustodyOrderListByRequestNoList(List<String> requestNoList) {
		List<ProjectInvestCustodyOrderDTO> result = new ArrayList<ProjectInvestCustodyOrderDTO>();
		List<ProjectInvestCustodyOrder> projectInvestCustodyOrderList = projectInvestCustodyOrderMapperExt.queryProjectInvestCustodyOrderListByRequestNoList(requestNoList);
		if (projectInvestCustodyOrderList != null) {
			for (ProjectInvestCustodyOrder projectInvestCustodyOrder : projectInvestCustodyOrderList) {
				if (projectInvestCustodyOrder != null) {
					ProjectInvestCustodyOrderDTO dto = new ProjectInvestCustodyOrderDTO();
					BeanUtils.copyProperties(projectInvestCustodyOrder, dto);
					result.add(dto);
				}
			}
		}
		return result;
	}

	/**
	 * 生成投资取消存管订单
	 *
	 * @param projectInvestCancelOrderDTO
	 * @return
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public ProjectInvestCustodyOrder generateInvestCancelCustodyOrder(ProjectInvestCancelOrderDTO projectInvestCancelOrderDTO) {
		Long investOrderId = projectInvestCancelOrderDTO.getId();
		ProjectInvestCustodyOrder projectInvestCustodyOrder = projectInvestCustodyOrderMapperExt.selectByInvestOrderIdAndType(investOrderId, Byte.valueOf("1"));
		projectInvestCustodyOrder = projectInvestCustodyOrderMapperExt.selectByPrimaryKeyForUpdate(projectInvestCustodyOrder.getId());
		ProjectInvestCustodyOrder record = projectInvestCustodyOrderMapperExt.selectByInvestOrderIdAndType(investOrderId, Byte.valueOf("2"));
		if (null == record) {
			record = new ProjectInvestCustodyOrder();
			record.setId(snowflakeIdWorker.nextId());
			record.setInvestOrderId(projectInvestCancelOrderDTO.getId());
			record.setInvestType(projectInvestCustodyOrder.getInvestType());
			record.setUserId(projectInvestCancelOrderDTO.getUserId());
			record.setAccountId(projectInvestCancelOrderDTO.getAccountId());
			record.setProjectId(projectInvestCustodyOrder.getProjectId());
			record.setBorrowUserId(projectInvestCustodyOrder.getBorrowUserId());
			record.setProjectType(projectInvestCancelOrderDTO.getProjectType());
			record.setProjectTitle(projectInvestCancelOrderDTO.getProjectTitle());
			record.setDeadline(projectInvestCancelOrderDTO.getDeadline());
			record.setDeadlineUnit(projectInvestCancelOrderDTO.getDeadlineUnit());
			record.setRequestNo(lanMaoSequence.getRequestNo());
			record.setPlatformUserNo(String.valueOf(projectInvestCancelOrderDTO.getAccountId()));
			record.setProjectNo(String.valueOf(projectInvestCancelOrderDTO.getProjectId()));
			record.setAmount(projectInvestCancelOrderDTO.getAmount());
			record.setPreTransactionNo(projectInvestCustodyOrder.getRequestNo());
			record.setType(Byte.valueOf("2"));
			record.setCreateTime(new Date());
			projectInvestCustodyOrderMapperExt.insertSelective(record);
		}
		return record;
	}

	@Transactional(isolation = Isolation.READ_COMMITTED)
	public void investCancelCustodyOrderSuccess(Long investCancelId) {
		ProjectInvestCustodyOrder projectInvestCustodyOrder = projectInvestCustodyOrderMapperExt.selectByPrimaryKeyForUpdate(investCancelId);
		if (Byte.valueOf("0").equals(projectInvestCustodyOrder.getStatus())) {
			ProjectInvestCustodyOrder updater = new ProjectInvestCustodyOrder();
			updater.setId(investCancelId);
			updater.setStatus(Byte.valueOf("1"));
			projectInvestCustodyOrderMapperExt.updateByPrimaryKeySelective(updater);
			// 智能投使用单笔失败
			if (OrderInvestTypeEnum.INTELLIGENCE.getType().equals(projectInvestCustodyOrder.getInvestType())) {
				billFacade.billIntelligenceInvestForRealProjectFail(projectInvestCustodyOrder.getUserId(), projectInvestCustodyOrder.getInvestOrderId() + "");
			} else {
				// 增加投资账户余额 + 记账
				billFacade.closeAndRevertBill(projectInvestCustodyOrder.getInvestOrderId().toString(), OrderTypeEnum.INVEST, BillRemark3Enum.INVEST_FLOW_BACK_AMOUNT.getDesc());
			}

			// 投资人投资冻结金额解冻
			MoneyTotalDTO investFreeze = new MoneyTotalDTO();
			investFreeze.setAmountType(AccountAmountTypeEnum.INVEST_FREEZE);
			investFreeze.setAmount(projectInvestCustodyOrder.getAmount().negate());
			investFreeze.setUserId(projectInvestCustodyOrder.getUserId());
			investFreeze.setAccountId(projectInvestCustodyOrder.getAccountId());
			moneyTotalLocalService.moneyTotal(investFreeze);
		}
	}

	@Transactional
	public void deleteProjectInvestCustodyOrder(Long id) {
		projectInvestCustodyOrderMapperExt.deleteByPrimaryKey(id);
	}

	/**
	 * 智能投订单存在获取历史数据，不存在生成新的历史数据 当历史数据存在失败的直接返回null
	 * 
	 * @param projectPackageOrderId
	 * @return
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public List<ProjectInvestCustodyOrder> generatePackageInvest(Long projectPackageOrderId) {
		//存在主订单，则返回历史数据，主订单状态如果为失败则返回null
		ProjectInvestCustodyOrder mainOrder = projectInvestCustodyOrderMapperExt.selectByInvestOrderIdAndType(projectPackageOrderId, Byte.valueOf("1"));
		if (Objects.nonNull(mainOrder)) {
			if (!Byte.valueOf("2").equals(mainOrder.getStatus())) {
				return projectInvestCustodyOrderMapperExt.subPackageInvestOrder(projectPackageOrderId, Byte.valueOf("1"));
			}
			return null;
		}
		//获取子订单信息
		List<IntelligencePayInfoResponseDTO> payInfoResponseDTOs = intelligenceInvestDubboService.getIntelligencePayInfo(projectPackageOrderId);
		//不存在主订单，则生成主订单以及子订单
		List<ProjectInvestCustodyOrder> result  = new ArrayList<>();
		String userId = payInfoResponseDTOs.get(0).getUserId();
		// 个人查询不存在查询机构
		AccountBase accountBase = accountService.getNiiwooAccount(userId, UserRoleEnum.INVESTOR);
		if (Objects.isNull(accountBase)) {
			accountBase = accountService.getOrgAccount(userId, userId);
		}
		if (Objects.isNull(accountBase)) {
			throw new BizException("ACC10001");// 存管账户未开通
		}
		ProjectInvestCustodyOrder custodyOrder = null;
		//子订单生成
		for (IntelligencePayInfoResponseDTO payInfo : payInfoResponseDTOs) {
			custodyOrder = new ProjectInvestCustodyOrder();
			custodyOrder.setAccountId(accountBase.getId());
			custodyOrder.setAmount(payInfo.getInvestAmount());
			custodyOrder.setBorrowUserId(payInfo.getBorrowerUserId());
			custodyOrder.setCreateTime(new Date());
			custodyOrder.setDeadline(payInfo.getDeadline());
			custodyOrder.setDeadlineUnit(payInfo.getDeadlineUnit());
			custodyOrder.setId(snowflakeIdWorker.nextId());
			custodyOrder.setInvestOrderId(payInfo.getInvestOrderId());
			custodyOrder.setPlatformUserNo(accountBase.getAccountNo());
			custodyOrder.setProjectId(projectPackageOrderId);//智能投投资订单占用标ID
			custodyOrder.setProjectNo(payInfo.getProjectId() + "");
			custodyOrder.setProjectTitle(payInfo.getProjectTitle());
			custodyOrder.setProjectType(payInfo.getProjectType());
			custodyOrder.setRequestNo(lanMaoSequence.getRequestNo());
			custodyOrder.setStatus(Byte.valueOf("0"));
			custodyOrder.setType(Byte.valueOf("1"));
			custodyOrder.setUpdateTime(new Date());
			custodyOrder.setUserId(payInfo.getUserId());
			custodyOrder.setInvestType(Byte.valueOf("3"));
			projectInvestCustodyOrderMapperExt.insertSelective(custodyOrder);
			result.add(custodyOrder);
		}
		//主订单
		custodyOrder = new ProjectInvestCustodyOrder();
		custodyOrder.setAccountId(accountBase.getId());
		custodyOrder.setAmount(BigDecimal.ZERO);
		custodyOrder.setBorrowUserId("-1");
		custodyOrder.setCreateTime(new Date());
		custodyOrder.setDeadline(1);
		custodyOrder.setDeadlineUnit(Byte.valueOf("1"));
		custodyOrder.setId(snowflakeIdWorker.nextId());
		custodyOrder.setInvestOrderId(projectPackageOrderId);
		custodyOrder.setPlatformUserNo(accountBase.getAccountNo());
		custodyOrder.setProjectId(projectPackageOrderId);
		custodyOrder.setProjectNo("-1");
		custodyOrder.setProjectTitle("-1");
		custodyOrder.setProjectType(Byte.valueOf("1"));
		custodyOrder.setRequestNo(lanMaoSequence.getRequestNo());
		custodyOrder.setStatus(Byte.valueOf("0"));
		custodyOrder.setType(Byte.valueOf("1"));
		custodyOrder.setUpdateTime(new Date());
		custodyOrder.setUserId(userId);
		custodyOrder.setInvestType(Byte.valueOf("3"));
		projectInvestCustodyOrderMapperExt.insertSelective(custodyOrder);
		return result;
	}

	/**
	 * 修改订单状态为成功
	 * 
	 * @param id
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public void intelligenceInvestCustodyOrderSuccess(Long id) {
		ProjectInvestCustodyOrder custodyOrder = new ProjectInvestCustodyOrder();
		custodyOrder.setId(id);
		custodyOrder.setStatus(Byte.valueOf("1"));
		projectInvestCustodyOrderMapperExt.updateByPrimaryKeySelective(custodyOrder);
	}

	/**
	 * 
	 * @param projectPackageOrderId
	 * @return
	 */
	@Transactional(isolation = Isolation.READ_COMMITTED)
	public List<ProjectInvestCustodyOrder> generatePackageInvestCancel(Long projectPackageOrderId) {
		 
		//存在处理中的直接返回订单历史数据，否则新生成
		ProjectInvestCustodyOrder mainCancelCustodyOrder =projectInvestCustodyOrderMapperExt.selectByInvestOrderIdAndType(projectPackageOrderId, Byte.valueOf("2"));
		if(Objects.nonNull(mainCancelCustodyOrder)) {
			if(!Byte.valueOf("0").equals(mainCancelCustodyOrder.getStatus())) {
				return null;
			}else {
			return	projectInvestCustodyOrderMapperExt.subPackageInvestOrder(projectPackageOrderId, Byte.valueOf("2"));
			}
		}
		 
		//生成撤销子订单
		List<ProjectInvestCustodyOrder> result =  projectInvestCustodyOrderMapperExt.subPackageInvestOrder(projectPackageOrderId, Byte.valueOf("1"));
		if (CollectionUtils.isEmpty(result)) {
			logger.warn("智能投订单未发起存管，但是发起了撤投，订单编号{}", projectPackageOrderId);
			throw new NullPointerException("智能投订单未发起存管，但是发起了撤投，订单编号" + projectPackageOrderId);
		}
		List<ProjectInvestCustodyOrder> cancelOrders = new ArrayList<>();
		for (ProjectInvestCustodyOrder projectInvestCustodyOrder : result) {
			ProjectInvestCustodyOrder custodyOrder = new ProjectInvestCustodyOrder();
			// 初始化状态的需要改失败状态，其他的状态不动
			if (Byte.valueOf("0").equals(projectInvestCustodyOrder.getStatus())) {
				custodyOrder.setUpdateTime(new Date());
				custodyOrder.setId(projectInvestCustodyOrder.getId());
				custodyOrder.setStatus(Byte.valueOf("2"));// 失败
				projectInvestCustodyOrderMapperExt.updateByPrimaryKeySelective(custodyOrder);
			}
			// 复制,生成解冻订单
			BeanUtils.copyProperties(projectInvestCustodyOrder, custodyOrder);
			custodyOrder.setId(snowflakeIdWorker.nextId());
			custodyOrder.setRequestNo(lanMaoSequence.getRequestNo());
			custodyOrder.setPreTransactionNo(projectInvestCustodyOrder.getRequestNo());
			custodyOrder.setType(Byte.valueOf("2"));
			custodyOrder.setStatus(Byte.valueOf("0"));
			custodyOrder.setCreateTime(new Date());
			custodyOrder.setUpdateTime(new Date());

			cancelOrders.add(custodyOrder);
			projectInvestCustodyOrderMapperExt.insert(custodyOrder);
		}
		//生成取消订单
		ProjectInvestCustodyOrder mainInvestCustodyOrder = projectInvestCustodyOrderMapperExt.selectByInvestOrderIdAndType(projectPackageOrderId, Byte.valueOf("1"));
		ProjectInvestCustodyOrder investCustodyOrder = new ProjectInvestCustodyOrder();
		investCustodyOrder.setId(mainInvestCustodyOrder.getId());
		investCustodyOrder.setStatus(Byte.valueOf("2"));
		investCustodyOrder.setUpdateTime(new Date());
		//投资订单改为失败
		projectInvestCustodyOrderMapperExt.updateByPrimaryKeySelective(investCustodyOrder);
		
		mainCancelCustodyOrder = new ProjectInvestCustodyOrder();
		BeanUtils.copyProperties(mainInvestCustodyOrder, mainCancelCustodyOrder);
		mainCancelCustodyOrder.setId(snowflakeIdWorker.nextId());
		mainCancelCustodyOrder.setStatus(Byte.valueOf("0"));
		mainCancelCustodyOrder.setCreateTime(new Date());
		mainCancelCustodyOrder.setUpdateTime(new Date());
		mainCancelCustodyOrder.setType(Byte.valueOf("2"));
		mainCancelCustodyOrder.setRequestNo(lanMaoSequence.getRequestNo());
		projectInvestCustodyOrderMapperExt.insertSelective(mainCancelCustodyOrder);
		return cancelOrders;
	}

	/**
	 * 通知账户中心投资存管成功
	 * 
	 * @param packageInvestOrderId
	 * @param projectInvestCustodyOrders
	 */
	@Transactional(isolation=Isolation.READ_COMMITTED)
	public void intelligenceInvestSuccess(Long packageInvestOrderId, List<ProjectInvestCustodyOrder> projectInvestCustodyOrders) {
		
		ProjectInvestCustodyOrder custodyOrder =projectInvestCustodyOrderMapperExt.selectByInvestOrderIdAndType(packageInvestOrderId, Byte.valueOf("1"));
		ProjectInvestCustodyOrder custodyOrderForUpdate = projectInvestCustodyOrderMapperExt.selectByPrimaryKeyForUpdate(custodyOrder.getId());
		//状态已经变更不做记账，幂等或者异常失败
		if(!Byte.valueOf("0").equals(custodyOrder.getStatus())) {
			return;
		}
		custodyOrderForUpdate.setStatus(Byte.valueOf("1"));
		custodyOrderForUpdate.setUpdateTime(new Date());
		projectInvestCustodyOrderMapperExt.updateByPrimaryKeySelective(custodyOrderForUpdate);
		
		String userId = custodyOrderForUpdate.getUserId();
		Long accountId = custodyOrderForUpdate.getAccountId();
		BigDecimal amount = BigDecimal.ZERO;
		for (ProjectInvestCustodyOrder projectInvestCustodyOrder : projectInvestCustodyOrders) {
			// 记账幂等
			BillIntelligenceInvestForMahchRequest request = new BillIntelligenceInvestForMahchRequest();
			request.setAmount(projectInvestCustodyOrder.getAmount());
			request.setPackageOrderId(packageInvestOrderId + "");
			request.setOrderId(projectInvestCustodyOrder.getInvestOrderId());
			request.setProjectId(Long.valueOf(projectInvestCustodyOrder.getProjectNo()));
			request.setProjectTitle(projectInvestCustodyOrder.getProjectTitle());
			request.setProjectTypeEnum(BorrowProjectTypeEnum.enumOf(projectInvestCustodyOrder.getProjectType()));
			ProjectDTO projectDTO = projectDubboService.selectProjectById(Long.valueOf(projectInvestCustodyOrder.getProjectNo()));
			request.setRelationAccountId(projectDTO.getBorrowAccountId());
			request.setLoanTypeEnum(LoanTypeEnum.enumOf(projectDTO.getLoanType()));
			request.setUserId(projectInvestCustodyOrder.getUserId());
			request.setRequestNo(projectInvestCustodyOrder.getRequestNo());
			billFacade.billIntelligenceInvestForMahch(request);
			amount = amount.add(projectInvestCustodyOrder.getAmount());
		}
		// 财富记账
		MoneyTotalDTO investFreeze = new MoneyTotalDTO();
		investFreeze.setAmountType(AccountAmountTypeEnum.INVEST_FREEZE);
		investFreeze.setAmount(amount);
		investFreeze.setUserId(userId);
		investFreeze.setAccountId(accountId);
		moneyTotalLocalService.moneyTotal(investFreeze);

	}

	/**
	 * 智能投投资失败
	 * 
	 * @param projectPackageOrderId
	 */
	@Transactional
	public void intelligenceInvestFalse(Long projectPackageOrderId) {
		ProjectInvestCustodyOrder custodyOrder =projectInvestCustodyOrderMapperExt.selectByInvestOrderIdAndType(projectPackageOrderId, Byte.valueOf("2"));
		ProjectInvestCustodyOrder newCustodyOrder = new ProjectInvestCustodyOrder();
		newCustodyOrder.setId(custodyOrder.getId());
		newCustodyOrder.setUpdateTime(new Date());
		newCustodyOrder.setStatus(Byte.valueOf("1"));
		projectInvestCustodyOrderMapperExt.updateByPrimaryKeySelective(newCustodyOrder);
		// 资金解冻
		billFacade.billIntelligenceInvestCancel(custodyOrder.getUserId(), projectPackageOrderId + "");
	}

}
